﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Reflection;
using System.Data;
using Oracle.DataAccess.Client;

namespace Petaframe.DataAccess
{

    /// <summary>
    /// Oracle veritabanına özel işlemler için kullanılır.
    /// </summary>
    public class OracleDataService : DataService, IOracleDataService
    {
         
        public OracleDataService(string serviceConnectionString)
            : base(serviceConnectionString, new OracleParameterBuilder(), new OracleEscapeSqlIdentifier(),DbProviderFactories.GetFactory("Oracle.DataAccess.Client"))
        {
                      
           
        }
      
        //public  object Insert<T>(T item)
        //{
        //    //TableInfo table = ClassDecomposer.ForEntity(item, new OracleParameterBuilder(), new SqlServerEscapeSqlIdentifier());
        //    var info = EntityQueryCache.GetTableQueriesAndInfo(item, _parameterBuilder, _escapeIdentifier);
        //    ISqlCommandStringBuilder insertCommand ;

        //    OpenConnection();          

        //    //eğer tabloda primary key varsa insert işleminden sonra primarykey değerini döndürecek komutu oluştur
        //    if (info.Item2.HasPrimaryKey)
        //    {
        //        insertCommand=new OracleReturningInsertCommandBuilder();
        //        DbCommand.CommandText = insertCommand.CommandString(info.Item2).ToSqlCommandString();               
        //    }
        //    else//primarykey yoksa int değer döndüren komutu oluştur
        //    {
        //        //insertCommand = new SqlInsertCommandBuilder();
        //        //DbCommand.CommandText = insertCommand.CommandString(info.Item2).ToSqlCommandString();
        //        DbCommand.CommandText = info.Item1.InsertQuery;
        //    }

        //    foreach (var column in info.Item2.Properties)
        //    {
        //       // ParameterInfo paramInfo = info.Item2.Parameters[column.PropertyName];

        //        if (!column.PrimaryKey | !column.AutoIncrement)
        //        {
        //            DbParameter parameter = column.ParameterInfo.DatabaseParameter;
        //            parameter.Value = ParameterInfo.GetParameterValue(column.CurrentPropertyDetails, item) ?? DBNull.Value;
        //            DbCommand.Parameters.Add(parameter);                   
        //        }
        //        else
        //        {
        //            DbParameter parameter = column.ParameterInfo.DatabaseParameter;
        //            parameter.Direction = ParameterDirection.Output;
        //            DbCommand.Parameters.Add(parameter);
        //        }
        //    }

        //    object result = DbCommand.ExecuteNonQuery();

           

        //    CloseConnection();
           
        //    return result;
        //}

        /// <summary>
        /// Sorgu sonucunu sayfalamak için kullanılır.
        /// </summary>
        /// <typeparam name="T">Sorgu için kullanılacak sınıf.</typeparam>
        /// <param name="currentPage">Sayfa numarası.</param>
        /// <param name="pageSize">Bir sayfada gösterilecek olan satır sayısı.</param>
        /// <param name="whereCommand">Where komutu.</param>
        /// <param name="orderByCommand">Order by komutu.</param>
        /// <returns><see cref="PagedResults"/> sınıfı içine konulmuş sorgu sonucu </returns>
        public override PagedResults<T> Page<T>(int currentPage = 1, int pageSize = 20, string whereCommand = "",string orderByCommand="")
        {
           // TableInfo table = ClassDecomposer.ForType(typeof(T), new OracleParameterBuilder(), new SqlServerEscapeSqlIdentifier());
            var table = EntityQueryCache.GetCachedTableInfo(Activator.CreateInstance<T>(), _parameterBuilder, _escapeIdentifier,_dbProviderFactory);
            PagedResults<T> page = new PagedResults<T>();

            currentPage = currentPage < 1 ? 1 : currentPage;
            pageSize=pageSize<1 ? 1 :pageSize;

            if (!string.IsNullOrEmpty(whereCommand))
            {
                if (!whereCommand.Trim().StartsWith("where", StringComparison.OrdinalIgnoreCase))
                {
                    whereCommand = "WHERE " + whereCommand;
                }
            }

            string cmd = string.Format("SELECT * FROM (SELECT a.*, rownum r__   FROM   ( SELECT * FROM {0} {3} ) a  WHERE rownum < (({1} * {2}) + 1 )) WHERE r__ >= ((({1}-1) * {2}) + 1) {4} ", table.TableName, currentPage, pageSize, whereCommand, orderByCommand);

            //toplam satır sayısını al           
            page.TotalRecords = Convert.ToInt32(GetScalarValue(string.Format("select count(*) from {0} {1}", table.TableName,whereCommand)));

            page.TotalPages = page.TotalRecords / pageSize;
            if (page.TotalRecords % pageSize > 0)
                page.TotalPages += 1;

            page.items = FindAll<T>(cmd);

            return page;
        }

        /// <summary>
        /// Output tipinden parametre eklemek için kullanılır.
        /// </summary>
        /// <param name="parameterName">Parametre adı.</param>
        /// <param name="dataType">Parametrenin veritabanı tipi</param>
        /// <param name="parameterSize">Parametrenin veritabanı sütununda kapladığı alan.Bu değer int ,double gibi tiplerde sıfırdır.</param>
        public  void AddOutputParameter(string parameterName, OracleDbType dbType, int parameterSize)
        {
            OracleParameter p = _dbProviderFactory.CreateParameter() as OracleParameter;
            p.OracleDbTypeEx = dbType;
            p.ParameterName = parameterName;
            p.Direction = ParameterDirection.Output;           
            _dbParameterList.Add(p); 
        }

        /// <summary>
        /// Input Output tipinden parametre eklemek için kullanılır.
        /// </summary>
        /// <param name="parameterName">Parametre adı.</param>
        /// <param name="parameterValue">Parametre değeri</param>
        /// <param name="dataType">Parametrenin veritabanı tipi</param>
        /// <param name="parameterSize">Parametrenin veritabanı sütununda kapladığı alan.Bu değer int ,double gibi tiplerde sıfırdır.</param>
        public void AddInputOutputParameter(string parameterName, object parameterValue, OracleDbType dbType, int parameterSize)
        {
            OracleParameter p = _dbProviderFactory.CreateParameter() as OracleParameter;
            p.OracleDbTypeEx = dbType;
            p.ParameterName = parameterName;
            p.Direction = ParameterDirection.InputOutput;
            p.Value = parameterValue ?? DBNull.Value;
            _dbParameterList.Add(p);    
        }

        /// <summary>
        /// Input tipinden parametre eklemek için kullanılır.
        /// </summary>
        /// <param name="parameterName">Parametre adı.</param>
        /// <param name="parameterValue">Parametre değeri</param>
        /// <param name="dataType">Parametrenin veritabanı tipi</param>
        public void AddInputParameter(string parameterName, object parameterValue, OracleDbType dbType)
        {
            OracleParameter p =  _dbProviderFactory.CreateParameter() as OracleParameter;
            p.OracleDbTypeEx = dbType;
            p.ParameterName = parameterName;
            p.Direction = ParameterDirection.Input;
            p.Value = parameterValue ?? DBNull.Value;
            _dbParameterList.Add(p);    
        }
    }
}
